package com.supermarket.manage.business.ucenter.controller;

import com.supermarket.manage.business.ucenter.config.AuthMessageConfig;
import com.supermarket.manage.common.constant.CodeConstant;
import com.supermarket.manage.common.dto.CodeStatus;
import com.supermarket.manage.common.dto.ResponseResult;
import com.supermarket.manage.common.dto.ucenter.request.*;
import com.supermarket.manage.common.dto.ucenter.response.UserAndTokenResponse;
import com.supermarket.manage.common.pojo.MyUser;
import com.supermarket.manage.common.utils.MapperUtils;
import com.supermarket.manage.common.utils.OkHttpClientUtil;
import com.supermarket.manage.common.utils.TimeUtil;
import com.supermarket.manage.common.validation.CheckGroup;
import com.supermarket.manage.provider.api.message.CodeService;
import com.supermarket.manage.provider.api.ucenter.BuyerService;
import com.supermarket.manage.provider.api.ucenter.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author Faxon
 * @version 1.0
 * @date 2020-02-18 18:18
 **/
@RestController
@RequestMapping("/user")
@Api(value = "UserController", tags = "用户接口")
public class UserController {

    @Reference(version = "1.0.0", timeout = 5000)
    private UserService userService;

    @Reference(version = "1.0.0", timeout = 5000)
    private BuyerService buyerService;

    @Resource
    private TokenStore tokenStore;

    @Resource
    private AuthMessageConfig authMessageConfig;

    @Resource
    private BCryptPasswordEncoder passwordEncoder;

    @Reference(version = "1.0.0", timeout = 5000)
    private CodeService codeService;

    @GetMapping("/checkShopName/{shopName}")
    @ApiOperation(value = "检查超市名称是否被使用", notes = "检查超市名称是否被使用")
    public ResponseResult<Void> checkShopName(@NotBlank(message = "超市名称不能为空") @PathVariable String shopName) {
        if (buyerService.getCountByShopName(shopName) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "该超市名称已被使用");
        }
        return new ResponseResult<>(CodeStatus.OK, "超市名可以使用");
    }

    @GetMapping("/checkUserName/{username}")
    @ApiOperation(value = "检查用户名是否被使用", notes = "检查用户名是否被使用")
    public ResponseResult<Void> checkUserName(@NotBlank(message = "用户名不能为空") @PathVariable String username) {
        if (userService.getCountByUsername(username) > 0 || buyerService.getCountByName(username) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "该用户名已被使用");
        }
        return new ResponseResult<>(CodeStatus.OK, "用户名可以使用");
    }

    @GetMapping("/checkPhoneNumber/{phoneNumber}")
    @ApiOperation(value = "检查用户号码是否被使用", notes = "检查用户号码是否被使用")
    public ResponseResult<Void> checkPhoneNumber(@NotBlank(message = "用户号码不能为空") @PathVariable String phoneNumber) {
        if (userService.getCountByPhone(phoneNumber) > 0 || buyerService.getCountByPhone(phoneNumber) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "用户号码已存在");
        }
        return new ResponseResult<>(CodeStatus.OK, "用户号码可以使用");
    }

    @PostMapping("/register")
    @ApiOperation(value = "用户注册", notes = "注册成功即生成超级管理员")
    public ResponseResult<Void> register(@Validated({CheckGroup.Add.class}) @RequestBody RegisterParams params) {
        if (buyerService.getCountByShopName(params.getShopName()) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "该超市名称已被使用");
        }
        if (userService.getCountByUsername(params.getUsername()) > 0 || buyerService.getCountByName(params.getUsername()) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "该用户名已被使用");
        }
        if (userService.getCountByPhone(params.getPhone()) > 0 || buyerService.getCountByPhone(params.getPhone()) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "用户号码已存在");
        }
        if (!codeService.checkPhoneCode(params.getPhone(), params.getCode())) {
            return new ResponseResult<>(CodeStatus.FAIL, "验证码错误或失效");
        }
        params.setPassword(passwordEncoder.encode(params.getPassword()));
        //注册客户信息与用户信息
        Boolean aBoolean = userService.register(params);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "注册成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "注册失败");
    }

    @PostMapping("/login")
    @ApiOperation(value = "通过用户名密码登录", notes = "通过用户名密码登录")
    public ResponseResult<UserAndTokenResponse> login(@Validated @RequestBody LoginParams loginParams) {
        MyUser myUser = userService.userLoginByUsername(loginParams.getUsername());
        if (null == myUser || !passwordEncoder.matches(loginParams.getPassword(), myUser.getPassword())) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, "用户名或密码错误");
        }
        Map<String, String> params = new HashMap<>(5);
        // 通过 HTTP 客户端请求登录接口
        params.put("username", loginParams.getUsername());
        params.put("password", loginParams.getPassword());
        params.put("grant_type", authMessageConfig.getGrant_type());
        params.put("client_id", authMessageConfig.getClient_id());
        params.put("client_secret", authMessageConfig.getClient_secret());
        UserAndTokenResponse userAndToken = new UserAndTokenResponse();
        BeanUtils.copyProperties(myUser, userAndToken);
        try {
            // 解析响应结果封装并返回
            Response response = OkHttpClientUtil.getInstance().postData(authMessageConfig.getUrl(), params);
            String jsonString = Objects.requireNonNull(response.body()).string();
            Map<String, Object> jsonMap = MapperUtils.json2map(jsonString);
            String accessToken = String.valueOf(jsonMap.get("access_token"));
            if (StringUtils.isBlank(accessToken) || "null".equals(accessToken)) {
                return new ResponseResult<>(CodeStatus.FAIL, "服务器异常：未获取到token");
            }
            userAndToken.setToken(accessToken);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResponseResult<>(CodeStatus.OK, "登录成功", userAndToken);
    }

    @PostMapping("/loginByPhone")
    @ApiOperation(value = "通过手机验证码登录", notes = "通过手机验证码登录")
    public ResponseResult<UserAndTokenResponse> loginByPhone(@Validated @RequestBody LoginByPhoneCodeParams params) {
        MyUser myUser = userService.userLoginByUsername(params.getPhoneNumber());
        if (null == myUser) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, "该手机号未注册本系统");
        }
        if (!codeService.checkPhoneCode(params.getPhoneNumber(), params.getCode())) {
            return new ResponseResult<>(CodeStatus.FAIL, "验证码错误或失效");
        }

        Map<String, String> map = new HashMap<>(5);
        // 通过 HTTP 客户端请求登录接口
        map.put("username", CodeConstant.PHONE_PREFIX + TimeUtil.getNowData() + params.getPhoneNumber());
        map.put("password", params.getCode());
        map.put("grant_type", authMessageConfig.getGrant_type());
        map.put("client_id", authMessageConfig.getClient_id());
        map.put("client_secret", authMessageConfig.getClient_secret());
        UserAndTokenResponse userAndToken = new UserAndTokenResponse();
        BeanUtils.copyProperties(myUser, userAndToken);
        try {
            // 解析响应结果封装并返回
            Response response = OkHttpClientUtil.getInstance().postData(authMessageConfig.getUrl(), map);
            String jsonString = Objects.requireNonNull(response.body()).string();
            Map<String, Object> jsonMap = MapperUtils.json2map(jsonString);
            String accessToken = String.valueOf(jsonMap.get("access_token"));
            if (StringUtils.isBlank(accessToken) || "null".equals(accessToken)) {
                return new ResponseResult<>(CodeStatus.FAIL, "验证码错误或失效");
            }
            userAndToken.setToken(accessToken);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResponseResult<>(CodeStatus.OK, "登录成功", userAndToken);
    }

    @PreAuthorize("hasAuthority('/logined')")
    @PostMapping(value = "/logout")
    @ApiOperation(value = "退出登录", notes = "退出登录")
    public ResponseResult<Void> logout(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        String token = authorization.replaceAll("Bearer ", "");
        // 删除 token 以注销
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
        tokenStore.removeAccessToken(oAuth2AccessToken);
        return new ResponseResult<Void>(CodeStatus.OK, "已退出");
    }


    @PreAuthorize("hasAuthority('/logined')")
    @PostMapping("/updatePasswordById")
    @ApiOperation(value = "修改密码", notes = "根据用户id修改密码")
    public ResponseResult<Void> updatePasswordById(@Validated @RequestBody UserPwdParams userPwdParams) {
        MyUser myUser = userService.getUserByUserId(userPwdParams.getId());
        if (myUser == null) {
            return new ResponseResult<>(CodeStatus.FAIL, "用户不存在");
        }
        //已绑定手机号的用户，用验证码校验身份
        if (StringUtils.isNotBlank(myUser.getPhone())) {
            if (StringUtils.isBlank(userPwdParams.getCode())) {
                return new ResponseResult<>(CodeStatus.FAIL, "已绑定手机号，请输入验证码");
            }
            Boolean checkPhoneCode = codeService.checkPhoneCode(myUser.getPhone(), userPwdParams.getCode());
            if (!checkPhoneCode) {
                return new ResponseResult<>(CodeStatus.FAIL, "验证码错误");
            }
        }
        //未保定手机号的用户，用原密码校验身份
        else {
            if (StringUtils.isBlank(userPwdParams.getOldPassword())) {
                return new ResponseResult<>(CodeStatus.FAIL, "未绑定手机号，请输入原密码验证您的身份");
            }
            if (!passwordEncoder.matches(userPwdParams.getOldPassword(), myUser.getPassword())) {
                return new ResponseResult<>(CodeStatus.FAIL, "密码错误");
            }
        }
        Boolean aBoolean = userService.updatePasswordById(userPwdParams.getId(), passwordEncoder.encode(userPwdParams.getNewPassword()));
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "修改成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "修改失败");
    }

    @PreAuthorize("hasAuthority('/logined')")
    @PostMapping("/updateUsernameById")
    @ApiOperation(value = "修改用户名", notes = "修改用户名")
    public ResponseResult<Void> updateUsernameById(@Validated({CheckGroup.UpdateName.class}) @RequestBody UserParams user) {
        MyUser myUser = userService.getUserByUserId(user.getId());
        if (myUser == null) {
            return new ResponseResult<>(CodeStatus.FAIL, "用户不存在");
        }
        MyUser newUser = new MyUser();
        if (StringUtils.isNotBlank(user.getUsername()) && !user.getUsername().equals(myUser.getUsername())) {
            Integer count = userService.getCountByUsername(user.getUsername());
            if (count > 1) {
                return new ResponseResult<>(CodeStatus.FAIL, "修改失败,用户名已被使用");
            } else {
                newUser.setId(user.getId());
                newUser.setBuyerId(user.getBuyerId());
                newUser.setUsername(user.getUsername());
                newUser.setUpdated(new Date());
            }
        } else {
            return new ResponseResult<>(CodeStatus.OK, "修改成功");
        }
        Boolean aBoolean = userService.updateUserById(newUser);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "修改成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "修改失败");
    }

    @PreAuthorize("hasAuthority('/logined')")
    @PostMapping("/bindPhone")
    @ApiOperation(value = "绑定手机号", notes = "绑定手机号（用户ID、手机号、验证码）")
    public ResponseResult<Void> bindPhone(@Validated({CheckGroup.UpdatePhone.class}) @RequestBody UserParams user) {
        if (!codeService.checkPhoneCode(user.getPhone(), user.getCode())) {
            return new ResponseResult<>(CodeStatus.FAIL, "验证码错误或失效");
        }
        if (userService.getCountByPhone(user.getPhone()) > 0) {
            return new ResponseResult<>(CodeStatus.FAIL, "该手机号已被使用");
        }
        Boolean aBoolean = userService.bindPhone(user);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "绑定成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "绑定失败");
    }

    @PreAuthorize("hasAuthority('/logined')")
    @PostMapping("/untiePhone")
    @ApiOperation(value = "解绑手机号", notes = "解绑手机号（用户ID、手机号、验证码）")
    public ResponseResult<Void> untiePhone(@Validated({CheckGroup.UpdatePhone.class}) @RequestBody UserParams user) {
        MyUser myUser = userService.getUserByUserId(user.getId());
        if (myUser == null) {
            return new ResponseResult<>(CodeStatus.FAIL, "用户不存在");
        }
        if (!myUser.getPhone().equals(user.getPhone())) {
            return new ResponseResult<>(CodeStatus.FAIL, "该手机号非当前用户手机号");
        }
        if (!codeService.checkPhoneCode(user.getPhone(), user.getCode())) {
            return new ResponseResult<>(CodeStatus.FAIL, "验证码错误或失效");
        }
        Boolean aBoolean = userService.untiePhone(user);
        if (aBoolean) {
            return new ResponseResult<>(CodeStatus.OK, "解绑成功");
        }
        return new ResponseResult<>(CodeStatus.FAIL, "解绑失败");
    }

}
